﻿using Magicodes.ExporterAndImporter.Excel;
using Microsoft.AspNetCore.Authorization;
using PHMEE.ToolKits;
using System.ComponentModel.DataAnnotations;
using System.Linq.Dynamic.Core;
using System.Text;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.IO;

namespace PHMEE.Admin.Application.Services.BaseInfo.Bears
{
    public class BearAppService : PHMEEAdminAppService, IBearAppService
    {
        private readonly IBearFactoryRepository bearFactoryRepository;
        private readonly IBearLibRepository bearLibRepository;
        private readonly IExcelImporter excelImporter;

        public BearAppService(IBearFactoryRepository bearFactoryRepository, IBearLibRepository bearLibRepository, IExcelImporter excelImporter)
        {
            this.bearFactoryRepository = bearFactoryRepository;
            this.bearLibRepository = bearLibRepository;
            this.excelImporter = excelImporter;
        }

        [Authorize(PHMEEAdminPermissions.BearFactories.Create)]
        public async Task<int> CreateBearFactoryAsync(BearFactoryCreateDto input)
        {
            var existingBearFactory = await bearFactoryRepository.FirstOrDefaultAsync(item => item.Name == input.Name);
            if (existingBearFactory != null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.BearFactoryNameAlreadyExist], PHMEEDomainErrorCodes.BearFactoryNameAlreadyExist).WithData("Name", input.Name);
            }
            var bearFactory = new BearFactory(input.Name);

            var createBearFactory = await bearFactoryRepository.PhmeeCreate(bearFactory);

            return createBearFactory.Id;
        }

        [Authorize(PHMEEAdminPermissions.BearFactories.Delete)]
        public async Task DeleteBearFactoryAsync(int id)
        {
            await bearFactoryRepository.PhmeeDelete(id);
        }

        [Authorize(PHMEEAdminPermissions.BearFactories.Default)]
        public async Task<BearFactoryDto> GetBearFactoryByIdAsync(int id)
        {
            BearFactory bearFactory = await bearFactoryRepository.PhmeeGetById(id);

            return ObjectMapper.Map<BearFactory, BearFactoryDto>(bearFactory);
        }

        [Authorize(PHMEEAdminPermissions.BearFactories.Default)]
        public async Task<PagedResultDto<BearFactoryDto>> GetPagedBearFactoriesAsync(BearFactoryListDto input)
        {
            var query = await bearFactoryRepository.PhmeeGetQuery();

            query = query.WhereIf(!string.IsNullOrEmpty(input.Name), item => item.Name.Contains(input.Name));

            if (input.Sorting != null)
            {
                query = query.OrderBy(input.Sorting);
            }
            else
            {
                query = query.OrderByDescending(item => item.CreationTime);
            }

            var totalCount = query.Count();

            if (input.IsPaged)
            {
                query = query.PageBy(input.SkipCount, input.MaxResultCount);
            }

            var bearFactories = await AsyncExecuter.ToListAsync(query);

            var items = ObjectMapper.Map<List<BearFactory>, List<BearFactoryDto>>(bearFactories);

            return new PagedResultDto<BearFactoryDto>(totalCount, items);
        }

        [Authorize(PHMEEAdminPermissions.BearFactories.Update)]
        public async Task UpdateBearFactoryAsync(BearFactoryUpdateDto input)
        {
            var query = await bearFactoryRepository.PhmeeGetQuery();

            if (query.Any(item => item.Name == input.Name && item.Id != input.Id))
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.BearFactoryNameAlreadyExist], PHMEEDomainErrorCodes.BearFactoryNameAlreadyExist).WithData("Name", input.Name);
            }

            var bearFactory = await bearFactoryRepository.PhmeeGetById(input.Id);

            if (bearFactory == null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.BearFactoryNotFound], PHMEEDomainErrorCodes.BearFactoryNotFound);
            }

            bearFactory.SetName(input.Name);

            await bearFactoryRepository.PhmeeUpdate(bearFactory);
        }



        [Authorize(PHMEEAdminPermissions.BearLibs.Create)]
        public async Task<Guid> CreateBearLibAsync(BearLibCreateDto input)
        {
            var existingBearFactory = await bearLibRepository.FirstOrDefaultAsync(item => item.Model == input.Model && item.BearFactoryId == input.BearFactoryId);
            if (existingBearFactory != null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.BearLibModelAlreadyExist], PHMEEDomainErrorCodes.BearLibModelAlreadyExist).WithData("Model", input.Model);
            }

            var id = GuidGenerator.Create();

            var bearLib = new BearLib(id, input.Model);

            bearLib.NB = input.NB;

            bearLib.BPFO = input.BPFO;

            bearLib.BPFI = input.BPFI;

            bearLib.FTFI = input.FTFI;

            bearLib.BSF = input.BSF;

            bearLib.ContactAngle = input.ContactAngle;

            bearLib.BearFactoryId = input.BearFactoryId;

            var createBearLib = await bearLibRepository.PhmeeCreate(bearLib);

            return createBearLib.Id;
        }

        [Authorize(PHMEEAdminPermissions.BearLibs.Delete)]
        public async Task DeleteBearLibAsync(Guid id)
        {
            await bearLibRepository.PhmeeDelete(id);
        }

        [Authorize(PHMEEAdminPermissions.BearLibs.Default)]
        public async Task<BearLibDto> GetBearLibByIdAsync(Guid id)
        {
            BearLib bearLib = await bearLibRepository.PhmeeGetById(id);

            return ObjectMapper.Map<BearLib, BearLibDto>(bearLib);
        }

        [Authorize(PHMEEAdminPermissions.BearLibs.Default)]
        public async Task<BearLibDto> GetBearLibByModelAsync(string model)
        {
            BearLib bearLib = await bearLibRepository.FirstOrDefaultAsync(item => item.Model == model);

            return ObjectMapper.Map<BearLib, BearLibDto>(bearLib);
        }

        [Authorize(PHMEEAdminPermissions.BearLibs.Default)]
        public async Task<PagedResultDto<BearLibDto>> GetPagedBearLibsAsync(BearLibListDto input)
        {
            var query = await bearLibRepository.PhmeeGetQuery();

            query = query.WhereIf(!string.IsNullOrEmpty(input.Model), item => item.Model.Contains(input.Model));

            if (input.Sorting != null)
            {
                query = query.OrderBy(input.Sorting);
            }
            else
            {
                query = query.OrderByDescending(item => item.CreationTime);
            }

            var totalCount = query.Count();

            if (input.IsPaged)
            {
                query = query.PageBy(input.SkipCount, input.MaxResultCount);
            }

            var bearLibs = await AsyncExecuter.ToListAsync(query);

            var items = ObjectMapper.Map<List<BearLib>, List<BearLibDto>>(bearLibs);

            return new PagedResultDto<BearLibDto>(totalCount, items);
        }

        [Authorize(PHMEEAdminPermissions.BearLibs.Update)]
        public async Task UpdateBearLibAsync(BearLibUpdateDto input)
        {
            var query = await bearLibRepository.PhmeeGetQuery();

            if (query.Any(item => item.Model == input.Model && item.BearFactoryId == input.BearFactoryId && item.Id != input.Id))
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.BearLibModelAlreadyExist], PHMEEDomainErrorCodes.BearLibModelAlreadyExist).WithData("Model", input.Model);
            }

            var bearLib = await bearLibRepository.PhmeeGetById(input.Id);

            if (bearLib == null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.BearLibNotFound], PHMEEDomainErrorCodes.BearLibNotFound);
            }

            bearLib.SetModel(input.Model);

            bearLib.NB = input.NB;

            bearLib.BPFO = input.BPFO;

            bearLib.BPFI = input.BPFI;

            bearLib.FTFI = input.FTFI;

            bearLib.BSF = input.BSF;

            bearLib.ContactAngle = input.ContactAngle;

            bearLib.BearFactoryId = input.BearFactoryId;

            await bearLibRepository.PhmeeUpdate(bearLib);
        }

        /// <summary>
        /// Excel模板存放的目录都是Templates
        /// </summary>
        /// <returns></returns>
        [Authorize(PHMEEAdminPermissions.BearLibs.DownloadTemplateExcel)]
        public async Task<byte[]> GenerateBearLibTemplateAsync()
        {
            string directoryPathTemplates = Path.Combine(Directory.GetCurrentDirectory(), "Templates");

            DirectoryHelper.CreateIfNotExists(directoryPathTemplates);

            var filePath = Path.Combine(directoryPathTemplates, "轴承库模板.xlsx");

            var result = await excelImporter.GenerateTemplate<BearLibImportDto>(filePath);

            var bytes = File.ReadAllBytes(filePath);

            return bytes;
        }

        [Authorize(PHMEEAdminPermissions.BearLibs.ImportExcel)]
        public async Task<OperationResult> ImportBearLibsAsync(byte[] bytes, string fileName)
        {
            var result = await excelImporter.ImportPhmeeExcelFile<BearLibImportDto>(bytes, fileName);

            if (!string.IsNullOrEmpty(result.Item2))
            {
                return OperationResult.Fail(result.Item2);
            }

            List<BearLibImportDto> importDtos = result.Item1.Data.ToList();

            List<BearLib> entities = new List<BearLib>();

            foreach (var importDto in importDtos)
            {
                BearLib model = new BearLib(importDto.Id, importDto.Model);

                model.BearFactoryId = importDto.BearFactoryId;
                model.NB = importDto.NB;
                model.BPFO = importDto.BPFO;
                model.BPFI = importDto.BPFI;
                model.FTFI = importDto.FTFI;
                model.BSF = importDto.BSF;
                model.ContactAngle = importDto.ContactAngle;
                model.CreationTime = DateTime.Now;
                model.CreatorId = CurrentUser.Id;

                entities.Add(model);
            }

            List<BearLib> entitiesExist = await bearLibRepository.PhmeeGetAll();

            var existingPairs = entitiesExist.Select(item => new { item.Model, item.BearFactoryId }).ToList();

            entities = entities.Where(item => !existingPairs.Any(existing => existing.Model == item.Model && existing.BearFactoryId == item.BearFactoryId)).ToList();

            await bearLibRepository.PhmeeCreateMany(entities);

            return OperationResult.SuccessResult();
        }

    }
}
